package org.aphelie.chronicle.shaper;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import org.aphelie.chronicle.ArcElement;
import org.aphelie.chronicle.ArcShape;
import org.aphelie.chronicle.ArcSheet;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;

public class ChronicleShaper {
	
	static final String EXTENSION_POINT_ID = "org.aphelie.chronicle.shaper";
	static final String EXTENSION_POINT_FILE = "filePath";
	
	public static List<ArcShape> Registry;
	
	private Map<String, ArcShape> topicMap;
	
	
	ChronicleShaper() {
		initRegistry();
		initShapeMap();
		
	}
	
	private void initRegistry() {
		List<ArcShape> shapes = new ArrayList<ArcShape>(); 
		for (IConfigurationElement configurationElement : Platform
				.getExtensionRegistry().getConfigurationElementsFor(
						ChronicleShaper.EXTENSION_POINT_ID)) {
			ArcShape shape = getShape(configurationElement);
			if (shape != null) {
				shapes.add(shape);
			}
		}
		Registry = Collections.unmodifiableList(shapes);
	}
	
	private void initShapeMap() {
		topicMap = new TreeMap<String, ArcShape>();
		for (ArcShape s : Registry) {
			initShapeMap(s);
		}
	}
	
	private void initShapeMap(ArcShape parent) {
		topicMap.put(parent.getId(), parent);
		for (ArcShape s : parent.getShapes()) {
			initShapeMap(s);
		}
	}

	private ArcShape getShape(IConfigurationElement configurationElement) {
		ArcShape shape = null;
		ResourceSet resourceSet = new ResourceSetImpl();
		try {
			IPath path = new Path("platform:/plugin/")
					.append(configurationElement.getNamespaceIdentifier())
					.append(configurationElement
							.getAttribute(ChronicleShaper.EXTENSION_POINT_FILE));
			// read shape
			URL url = new URL(path.toString());
			InputStream inputStream = url.openConnection()
					.getInputStream();
			// create resource
			URI uri = URI.createPlatformResourceURI(
					path.toString(), true);
			Resource resource = resourceSet.createResource(uri);
			resource.load(inputStream, resourceSet.getLoadOptions());
			// load the shape
			shape = (ArcShape) resource.getContents().get(0);
		} catch (IOException e) {
			// ignore missing resources
			e.printStackTrace();
		}
		return shape;
	}
	
	public ArcShape getShape(String id) {
		return findShape(id);
	}
	
	private ArcShape findShape(String id) {
		ArcShape shape;
		for (ArcShape s : Registry) {
			shape = findShape(id, s);
			if (shape != null) {
				return shape;
			}
		}
		return null;
	}
	
	private ArcShape findShape(String id, ArcShape parent) {
		if (parent.getId().equals(id)) {
			if (parent.getRefid() == null) {
				return parent;
			}
			return findShape(parent.getRefid());
		}
		if (id.equals(parent.getRefid())) {
			findShape(parent.getRefid());
		}
		ArcShape shape;
		for (ArcShape s : parent.getShapes()) {
			shape = findShape(id, s);
			if (shape != null) {
				return shape;
			}
		}
		return null;
	}

	public void shape(EObject object) {
		if (object == null || !(object instanceof ArcElement)) {
			return;
		}
		ArcShape shape = findShape(object.eClass().getName());
		if (shape == null) {
			return;
		}
		shape.shape((ArcSheet) object);
		
	}
	
}
